package org.anyline.simple.datasource;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.anyline.data.adapter.DriverAdapter;
import org.anyline.data.datasource.DataSourceMonitor;
import org.anyline.data.runtime.DataRuntime;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

@Component
public class MyBatisDataSourceMonitor implements DataSourceMonitor {
    private Map<String, String> features = new HashMap<>();
    private Map<String, DriverAdapter> adapters = new Hashtable<>();

    /**
     * 数据源特征 用来定准 adapter 包含数据库或JDBC协议关键字<br/>
     * 一般会通过 产品名_url 合成 如果返回null 上层方法会通过driver_产品名_url合成
     * @param datasource 数据源
     * @return String 返回null由上层自动提取
     */
    @Override
    public String feature(DataRuntime runtime, Object datasource) {
        String feature = null;
        if(datasource instanceof JdbcTemplate){
            JdbcTemplate jdbc = (JdbcTemplate)datasource;
            DataSource ds = jdbc.getDataSource();
            if(ds instanceof DynamicRoutingDataSource){
                String key = DynamicDataSourceContextHolder.peek();
                feature = features.get(key);
                if(null == feature){
                    Connection con = null;
                    try {
                        con = DataSourceUtils.getConnection(ds);
                        DatabaseMetaData meta = con.getMetaData();
                        String url = meta.getURL();
                        feature = meta.getDatabaseProductName().toLowerCase().replace(" ","") + "_" + url;
                        features.put(key, feature);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if (null != con && !DataSourceUtils.isConnectionTransactional(con, ds)) {
                            DataSourceUtils.releaseConnection(con, ds);
                        }
                    }
                }
            }
        }
        return feature;
    }

    /**
     * 数据源唯一标识 如果不实现则默认feature
     * @param datasource 数据源
     * @return String 返回null由上层自动提取
     */
    @Override
    public String key(DataRuntime runtime, Object datasource) {
        if(datasource instanceof JdbcTemplate){
            JdbcTemplate jdbc = (JdbcTemplate)datasource;
            DataSource ds = jdbc.getDataSource();
            if(ds instanceof DynamicRoutingDataSource){
                return DynamicDataSourceContextHolder.peek();
            }
        }
        return runtime.getKey();
    }
    /**
     * ConfigTable.KEEP_ADAPTER=2 : 根据当前接口判断是否保持同一个数据源绑定同一个adapter<br/>
     * DynamicRoutingDataSource类型的返回false,因为同一个DynamicRoutingDataSource可能对应多类数据库, 如果项目中只有一种数据库 应该直接返回true
     * @param datasource 数据源
     * @return boolean
     */
    @Override
    public boolean keepAdapter(DataRuntime runtime, Object datasource) {
        if(datasource instanceof JdbcTemplate){
            JdbcTemplate jdbc = (JdbcTemplate)datasource;
            DataSource ds = jdbc.getDataSource();
            if(ds instanceof DynamicRoutingDataSource){
                return false;
            }
        }
        return true;
    }







/* ********************************************************************************************************************
*
*
*                   下面是为了缓存adapter 实际测试发现没 定位一次基本会在1毫秒内完成  缓存没什么太大意义
*
*
 ******************************************************************************************************************** */

















    /**
     * 如果有根据feature识别不了的情况，可以在这里实现，如果这一步返回了adapter则以这一步为准
     * @param datasource 数据源
     * @return DriverAdapter
     */
    @Override
    public DriverAdapter adapter(DataRuntime runtime, Object datasource) {
        DriverAdapter adapter = null;
        if(datasource instanceof JdbcTemplate){
            JdbcTemplate jdbc = (JdbcTemplate)datasource;
            DataSource ds = jdbc.getDataSource();
            if(ds instanceof DynamicRoutingDataSource){
                String key = DynamicDataSourceContextHolder.peek();
                adapter = adapters.get(key);
            }
        }
        return adapter;
    }

    /**
     * 上层方法完成adapter定位后调用,可以在这里缓存,下一次定位提供给adapter(Object datasource)
     * @param runtime 运行环境主要包含驱动适配器 数据源或客户端
     * @param datasource 数据源
     * @param adapter DriverAdapter
     * @return 如果没有问题原样返回，如果有问题可以修正或返回null, 如果返回null上层方法会抛出adapter定位失败的异常
     */
    @Override
    public DriverAdapter after(DataRuntime runtime, Object datasource, DriverAdapter adapter) {
        if(datasource instanceof JdbcTemplate){
            JdbcTemplate jdbc = (JdbcTemplate)datasource;
            DataSource ds = jdbc.getDataSource();
            if(ds instanceof DynamicRoutingDataSource){
                String key = DynamicDataSourceContextHolder.peek();
                adapters.put(key, adapter);
            }
        }
        return adapter;
    }
}
